package com.khotyn.heresy.util;

import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Date;
import java.util.Iterator;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.MemoryCacheImageInputStream;

import com.drew.imaging.jpeg.JpegMetadataReader;
import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.metadata.Directory;
import com.drew.metadata.Metadata;
import com.drew.metadata.MetadataException;
import com.drew.metadata.exif.ExifDirectory;
import com.khotyn.heresy.bean.ImageEXIFInfo;
import com.sun.imageio.plugins.bmp.BMPImageReader;
import com.sun.imageio.plugins.gif.GIFImageReader;
import com.sun.imageio.plugins.jpeg.JPEGImageReader;
import com.sun.imageio.plugins.png.PNGImageReader;

/**
 * 图片处理工具类 2009.4.22:修改isImage函数的参数为File,以更好地和UploadService合作，
 * 修改getEXIFInfo函数的参数为File以更好地和UploadService合作，修改人：黄挺 2009.5.17增加生成缩略图功能
 * 
 * @author 王长乐
 * 
 */
public class ImageUtil {

	/**
	 *提取相片EXIF信息
	 * 
	 * @param jpegFile
	 *            欲提取信息的相片文件
	 *@return 所选相片EXIF类对象
	 * @throws IOException
	 */
	public static ImageEXIFInfo getEXIFInfo(File jpegFile)
			throws MetadataException, JpegProcessingException, IOException {

		ImageEXIFInfo exifBean = null;
		String filename = jpegFile.getName();
		String filetype = filename.substring(filename.lastIndexOf(".") + 1);
		FileInputStream fis = new FileInputStream(jpegFile);
		int leng = fis.available();
		BufferedInputStream buff = new BufferedInputStream(fis);
		byte[] mapObj = new byte[leng];
		buff.read(mapObj, 0, leng);
		boolean type = false;
		ByteArrayInputStream bais = null;
		MemoryCacheImageInputStream mcis = null;

		try {
			bais = new ByteArrayInputStream(mapObj);
			mcis = new MemoryCacheImageInputStream(bais);
			Iterator<ImageReader> itr = ImageIO.getImageReaders(mcis);

			while (itr.hasNext()) {
				ImageReader reader = (ImageReader) itr.next();

				if (("jpg".equalsIgnoreCase(filetype) || "jpeg"
						.equalsIgnoreCase(filetype))
						&& reader instanceof JPEGImageReader) {
					type = true;
				}
			}

		} finally {
			if (bais != null) {
				try {
					bais.close();
				} catch (IOException ioe) {

				}
			}

			if (mcis != null) {
				try {
					mcis.close();
				} catch (IOException ioe) {

				}
			}
		}

		if (type == true) {
			Metadata metadata = JpegMetadataReader.readMetadata(jpegFile);
			Directory exif = metadata.getDirectory(ExifDirectory.class);
			exifBean = new ImageEXIFInfo();

			if (exif.containsTag(ExifDirectory.TAG_MAKE)) {

				String camera_brand = exif
						.getDescription(ExifDirectory.TAG_MAKE);

				exifBean.setCamera_brand(camera_brand);

			}

			if (exif.containsTag(ExifDirectory.TAG_MODEL)) {

				String camera_model = exif
						.getDescription(ExifDirectory.TAG_MODEL);

				exifBean.setCamera_model(camera_model);

			}

			if (exif.containsTag(ExifDirectory.TAG_ISO_EQUIVALENT)) {

				String ISOstr = exif
						.getDescription(ExifDirectory.TAG_ISO_EQUIVALENT);

				int ISO = Integer.parseInt(ISOstr);

				exifBean.setIso(ISO);

			}

			if (exif.containsTag(ExifDirectory.TAG_EXPOSURE_TIME)) {

				String exposure = exif
						.getDescription(ExifDirectory.TAG_EXPOSURE_TIME);

				exifBean.setExposure(exposure);

			}

			if (exif.containsTag(ExifDirectory.TAG_APERTURE)) {

				String aperture = exif
						.getDescription(ExifDirectory.TAG_APERTURE);

				exifBean.setAperture(aperture);

			}

			if (exif.containsTag(ExifDirectory.TAG_FOCAL_LENGTH)) {

				String focal_length = exif
						.getDescription(ExifDirectory.TAG_FOCAL_LENGTH);

				exifBean.setFocal_length(focal_length);

			}

			if (exif.containsTag(ExifDirectory.TAG_FLASH)) {

				String photoflash = exif
						.getDescription(ExifDirectory.TAG_FLASH);

				exifBean.setPhotoflash(photoflash);

			}

			if (exif.containsTag(ExifDirectory.TAG_DATETIME)) {

				Date shut_time = exif.getDate(ExifDirectory.TAG_DATETIME);

				exifBean.setShut_time(shut_time);

			}

			return exifBean;
		} else {
			return exifBean;
		}
	}

	/**
	 * 判断文件是否为图片文件格式
	 * 
	 * @param file
	 *            欲判断的文件
	 *@return 当文件确实为图片格式时，返回TRUE
	 */
	public static boolean isImage(File file) throws IOException {

		String filename = file.getName();

		String filetype = filename.substring(filename.lastIndexOf(".") + 1);

		FileInputStream fis = new FileInputStream(file);

		int leng = fis.available();

		BufferedInputStream buff = new BufferedInputStream(fis);

		byte[] mapObj = new byte[leng];

		buff.read(mapObj, 0, leng);

		boolean type = false;

		ByteArrayInputStream bais = null;

		MemoryCacheImageInputStream mcis = null;

		try {

			bais = new ByteArrayInputStream(mapObj);

			mcis = new MemoryCacheImageInputStream(bais);

			Iterator<ImageReader> itr = ImageIO.getImageReaders(mcis);

			while (itr.hasNext()) {

				ImageReader reader = (ImageReader) itr.next();

				if ("gif".equalsIgnoreCase(filetype)
						&& reader instanceof GIFImageReader) {

					type = true;

				} else if (("jpg".equalsIgnoreCase(filetype) || "jpeg"
						.equalsIgnoreCase(filetype))
						&& reader instanceof JPEGImageReader) {

					type = true;

				} else if ("png".equalsIgnoreCase(filetype)
						&& reader instanceof PNGImageReader) {

					type = true;

				} else if ("bmp".equalsIgnoreCase(filetype)
						&& reader instanceof BMPImageReader) {

					type = true;
				}
			}

		} finally {
			if (bais != null) {
				try {
					bais.close();
				} catch (IOException ioe) {

				}
			}

			if (mcis != null) {
				try {
					mcis.close();
				} catch (IOException ioe) {

				}
			}
		}
		return type;
	}

	/**
	 * 图像缩放 - 参数指定目标图缩放比例。
	 * 
	 * @param srcImage
	 *            源图像对象。
	 * @param xscale
	 *            图像 x 轴（宽度）上的的缩放比例。
	 * @param yscale
	 *            图像 y 轴（高度）上的的缩放比例。
	 * @param hints
	 *            重新绘图使用的 RenderingHints 对象。
	 * @return 缩放后的图像对象。
	 */
	public static BufferedImage scaleJ2D(BufferedImage srcImage, double xscale,
			double yscale, RenderingHints hints) {

		AffineTransform affineTransform = new AffineTransform();
		affineTransform.scale(xscale, yscale);

		AffineTransformOp affineTransformOp = new AffineTransformOp(
				affineTransform, hints);

		int width = (int) ((double) srcImage.getWidth() * xscale);
		int height = (int) ((double) srcImage.getHeight() * yscale);
		BufferedImage dstImage = new BufferedImage(width, height, srcImage
				.getType());

		return affineTransformOp.filter(srcImage, dstImage);

	}

	/**
	 * 图像缩放 - 参数指定缩放后的目标图宽高。
	 * 
	 * @param srcImage
	 *            源图像对象。
	 * @param dstWidth
	 *            目标图的宽度。
	 * @param dstHeight
	 *            目标图的高度。
	 * @param hints
	 *            重新绘图使用的 RenderingHints 对象。
	 * @return 缩放后的图像对象。
	 */
	public static BufferedImage scaleJ2D(BufferedImage srcImage, int dstWidth,
			int dstHeight, RenderingHints hints) {
		float xscale = (float) dstWidth / (float) srcImage.getWidth();
		float yscale = (float) dstHeight / (float) srcImage.getHeight();

		return scaleJ2D(srcImage, xscale, yscale, hints);
	}

	/**
	 * 图像缩放 -参数指定图像缩放后的较长边的长度，较短边按比例缩放
	 * 
	 * @param imageFile
	 *            源图像文件
	 * @param imageSize
	 *            较长边缩放后的长度
	 * @return 缩放后图像对象
	 * @throws IOException
	 *             文件读取错误
	 */
	public static BufferedImage scaleJ2D(File imageFile, int imageSize)
			throws IOException {
		BufferedImage srcImage = ImageIO.read(imageFile);
		float xscale = 0;
		float yscale = 0;
		int srcWidth = srcImage.getWidth();
		int srcHeight = srcImage.getHeight();

		if (srcWidth < imageSize && srcHeight < imageSize)
			return srcImage;

		else if (srcWidth >= srcHeight) {
			xscale = (float) imageSize / (float) srcWidth;
			yscale = xscale;
		}

		else if (srcWidth < srcHeight) {
			yscale = (float) imageSize / (float) srcHeight;
			xscale = yscale;
		}

		return scaleJ2D(srcImage, xscale, yscale, new RenderingHints(
				RenderingHints.KEY_RENDERING,
				RenderingHints.VALUE_COLOR_RENDER_QUALITY));

	}

}